﻿using System;
using Gumini.JulaDB.DataTypes;
using Gumini.JulaDB.Enums;
using Gumini.JulaDB.Provider;

namespace Gumini.JulaDB.Expressions.Operators
{
    internal abstract class RelationalOperator : BinaryOperator
    {
        public RelationalOperator(params string[] names)
            : base(names) { }

        protected abstract bool EvaluateCore(object a, object b);

        public override TypedValue Evaluate(TypedValue left, TypedValue right)
        {
            // result of a comparison is undefined when at least one of the operands is undefined
            if (left.IsNull || right.IsNull)
                return TypedValue.Null;

            object a = left.Value;
            object b = right.Value;
            if (!left.Type.Equals(right.Type)) // types do not match, lets try to convert them both to numbers
            {
                var numberType = DataType.Number;
                try
                {
                    a = numberType.ConvertFrom(a);
                    b = numberType.ConvertFrom(b);
                }
                catch (Exception)
                {
                    throw new JulaDbException(ErrorCode.UnableToCompare,
                        "Unable to compare two expressions of types '{0}' and '{1}'.", left.Type, right.Type);
                }
            }

            return new TypedValue(DataType.Bool, EvaluateCore(a, b));
        }

        public override DataType GetReturnType()
        {
            return DataType.Bool;
        }
    }
}
